home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / program / ddj0897.zip / DYN401.ZIP / class / string.d < prev    next >
Text File  |  1996-08-16  |  17KB  |  975 lines

  1.  
  2. /*
  3.  *
  4.  *    Copyright (c) 1993-1996 Algorithms Corporation
  5.  *    3020 Liberty Hills Drive
  6.  *    Franklin, TN  37067
  7.  *
  8.  *    ALL RIGHTS RESERVED.
  9.  *
  10.  *
  11.  *
  12.  */
  13.  
  14.  
  15.  
  16. #include "memalloc.h"
  17. #include <ctype.h>
  18. #include <string.h>
  19. #include <math.h>
  20.  
  21. #if 0            /*  1 = auto reduction of string size if fum set */
  22. #define    ADJUST
  23. #endif
  24.  
  25.  
  26. defclass  String : Stream {
  27.     char    *iStr;
  28.     int    iSize;        /*  size of str buffer area    */
  29.     int    iLen;        /*  length of string        */
  30.     int    iBlksz;        /*  allocation block size    */
  31.     int    iCalcLen;
  32. //#ifdef    ADJUST
  33.     int    iFum;        /*  free unused memory flag    */
  34. //#endif
  35. };
  36.  
  37.  
  38.  
  39. /*  calculates correct size based on blksz  */
  40.  
  41. #define SETSIZE(x) iSize = ((x) ? (((x)-1)/iBlksz + 1) * iBlksz : 0)
  42.  
  43. #define ABS    40    /*  Default append block size    */
  44.  
  45. #define    UPDATE_LEN    if (iCalcLen)    iLen = strlen(iStr)
  46.  
  47.  
  48. #ifndef    max
  49. #define     max(a,b)    ((a) > (b)    ? (a) :    (b))
  50. #endif
  51.  
  52.  
  53. #ifdef    ADJUST
  54. #define FREE_UNUSED                        \
  55.     if (iFum  &&  iLen+1 <= iSize-iBlksz)  {        \
  56.         SETSIZE(iLen+1);                \
  57.         iStr = (char *) MA_realloc(iStr, iSize);    \
  58.     }
  59. #else
  60. #define FREE_UNUSED
  61. #endif
  62.  
  63.  
  64. static    int    get_string(object, char **, char *, int);
  65.  
  66.  
  67.  
  68. cmeth    gNewWithStr, <vNew> : New (char *so)
  69. {
  70.     object    obj = gNew(super);
  71.     ivType    *iv = ivPtr(obj);
  72.     char    *str;
  73.     int    len;
  74.  
  75.     len = get_string((object) so, &str, "New", 2);
  76.     iBlksz = 1;
  77.     SETSIZE(len + 1);
  78.     iStr = (char *) MA_malloc(iSize, &iStr);
  79.     if (len)
  80.         memcpy(iStr, str, len);
  81.     iStr[len] = '\0';
  82.     iLen = len;
  83.     return(obj);
  84. }
  85.  
  86. cmeth    gNewWithInt(int len)
  87. {
  88.     object    obj = gNew(super);
  89.     ivType    *iv = ivPtr(obj);
  90.  
  91.     iBlksz = 1;
  92.     SETSIZE(len + 1);
  93.     iStr = (char *) MA_malloc(iSize, &iStr);
  94.     *iStr = '\0';
  95.     iCalcLen = 1;
  96.     iLen = 0;
  97.     return(obj);
  98. }
  99.  
  100. cmeth    gNewWithObj(so)
  101. {
  102.     return New(self, (char *) so);
  103. }
  104.  
  105. cmeth    gNew()
  106. {
  107.     return New(self, "");
  108. }
  109.  
  110. imeth    char    *gStringValue()
  111. {
  112.     return iStr;
  113. }
  114.  
  115. imeth    int    gSize()
  116. {
  117.     UPDATE_LEN;
  118.     return iLen;
  119. }
  120.  
  121. imeth    gChangeValue : ChangeValue (obj)
  122. {
  123.     char    *str;
  124.     int    len;
  125.  
  126.     len = get_string(obj, &str, "ChangeValue", 2);
  127.     iLen = len;
  128.     if (len >= iSize)  {
  129.         SETSIZE(iLen + 1);
  130.         iStr = (char *) MA_realloc(iStr, iSize);
  131.     }
  132.     if (len)
  133.         memcpy(iStr, str, len);
  134.     iStr[len] = '\0';
  135.     FREE_UNUSED;
  136.     return self;
  137. }
  138.  
  139. imeth    gChangeStrValue(char *str)
  140. {
  141.     return ChangeValue(self, (object) str);
  142. }
  143.  
  144. imeth    object    gDispose, gDeepDispose, gGCDispose ()
  145. {
  146.     if (iStr)
  147.         MA_free(iStr);
  148.     return gDispose(super);
  149. }
  150.  
  151. imeth    int    gHash()
  152. {
  153.     register char     c = 'a';
  154.     char    *s = iStr;
  155.     double    t;
  156.     register unsigned short     k=0;  /* must be short     */
  157.  
  158.     while (*s)
  159.         k += *s++ ^ c++;
  160.     t = .6125423371    * k;
  161.     return (int) (BIG_INT * (t - floor(t)));
  162. }
  163.  
  164. imeth    int    gCompare(obj)
  165. {
  166.     char    *s, *t;
  167.     int    tlen, slen;
  168.  
  169.     if (IsObj(obj))  {
  170.         ivType    *iv2;
  171.  
  172.         if (!gIsKindOf(obj, CLASS))
  173.             return gCompare(super, obj);
  174.         iv2 = ivPtr(obj);
  175.         t = iv2->iStr;
  176.         if (iv2->iCalcLen)
  177.             iv2->iLen = strlen(t);
  178.         tlen = iv2->iLen;
  179.     } else {
  180.         t = (char *) obj;
  181.         tlen = t ? strlen(t) : 0;
  182.     }
  183.     UPDATE_LEN;
  184.     slen = iLen;
  185.     s = iStr;
  186.     while (slen  &&  tlen  &&  *s == *t)  {
  187.         s++;
  188.         t++;
  189.         slen--;
  190.         tlen--;
  191.     }
  192.     if (!slen  &&  !tlen)
  193.         return 0;
  194.     if (!slen)
  195.         return -1;
  196.     if (!tlen)
  197.         return 1;
  198.     return *(unsigned char *)s - *(unsigned char *)t;
  199. }
  200.  
  201. imeth    int    gCompareI(obj)
  202. {
  203.     char    *s, *t;
  204.     int    tlen, slen;
  205.  
  206.     if (IsObj(obj))  {
  207.         ivType    *iv2;
  208.  
  209.         if (!gIsKindOf(obj, CLASS))
  210.             gError(self, "CompareI::String:  Arg 2 incorrect type.\n");
  211.         iv2 = ivPtr(obj);
  212.         t = iv2->iStr;
  213.         if (iv2->iCalcLen)
  214.             iv2->iLen = strlen(t);
  215.         tlen = iv2->iLen;
  216.     } else {
  217.         t = (char *) obj;
  218.         tlen = t ? strlen(t) : 0;
  219.     }
  220.     UPDATE_LEN;
  221.     slen = iLen;
  222.     s = iStr;
  223.     while (slen  &&  tlen  &&  tolower(*s) == tolower(*t))  {
  224.         s++;
  225.         t++;
  226.         slen--;
  227.         tlen--;
  228.     }
  229.     if (!slen  &&  !tlen)
  230.         return 0;
  231.     if (!slen)
  232.         return -1;
  233.     if (!tlen)
  234.         return 1;
  235.     return tolower(*(unsigned char *)s) - tolower(*(unsigned char *)t);
  236. }
  237.  
  238. imeth    int    gCompareN(obj, int n)
  239. {
  240.     char    *s, *t;
  241.     int    tlen, slen;
  242.  
  243.     if (IsObj(obj))  {
  244.         ivType    *iv2;
  245.  
  246.         if (!gIsKindOf(obj, CLASS))
  247.             gError(self, "CompareN::String:  Arg 2 incorrect type.\n");
  248.         iv2 = ivPtr(obj);
  249.         t = iv2->iStr;
  250.         if (iv2->iCalcLen)
  251.             iv2->iLen = strlen(t);
  252.         tlen = iv2->iLen;
  253.     } else {
  254.         t = (char *) obj;
  255.         tlen = t ? strlen(t) : 0;
  256.     }
  257.     UPDATE_LEN;
  258.     slen = iLen;
  259.     s = iStr;
  260.     while (n  &&  slen  &&  tlen  &&  *s == *t)  {
  261.         s++;
  262.         t++;
  263.         n--;
  264.         slen--;
  265.         tlen--;
  266.     }
  267.     if (!n  ||  !slen  &&  !tlen)
  268.         return 0;
  269.     if (!slen)
  270.         return -1;
  271.     if (!tlen)
  272.         return 1;
  273.     return *(unsigned char *)s - *(unsigned char *)t;
  274. }
  275.  
  276. imeth    int    gCompareNI(obj, int n)
  277. {
  278.     char    *s, *t;
  279.     int    tlen, slen;
  280.  
  281.     if (IsObj(obj))  {
  282.         ivType    *iv2;
  283.  
  284.         if (!gIsKindOf(obj, CLASS))
  285.             gError(self, "CompareNI::String:  Arg 2 incorrect type.\n");
  286.         iv2 = ivPtr(obj);
  287.         t = iv2->iStr;
  288.         if (iv2->iCalcLen)
  289.             iv2->iLen = strlen(t);
  290.         tlen = iv2->iLen;
  291.     } else {
  292.         t = (char *) obj;
  293.         tlen = t ? strlen(t) : 0;
  294.     }
  295.     UPDATE_LEN;
  296.     slen = iLen;
  297.     s = iStr;
  298.     while (n  &&  slen  &&  tlen  &&  tolower(*s) == tolower(*t))  {
  299.         s++;
  300.         t++;
  301.         n--;
  302.         slen--;
  303.         tlen--;
  304.     }
  305.     if (!n  ||  !slen  &&  !tlen)
  306.         return 0;
  307.     if (!slen)
  308.         return -1;
  309.     if (!tlen)
  310.         return 1;
  311.     return tolower(*(unsigned char *)s) - tolower(*(unsigned char *)t);
  312. }
  313.  
  314. imeth    gStringRepValue()
  315. {
  316.     return vSprintf(String, "\"%s\"", iStr ? iStr : "(null)");
  317. }
  318.  
  319. imeth    int    gPrintLength(int t)      /* return the    print length of    s  */
  320. {
  321.     register int n=0;
  322.     int    l=0;
  323.     char    *s;
  324.  
  325.     UPDATE_LEN;
  326.     if (!iLen)
  327.         return(0);
  328.     for (s=iStr ; *s  &&  *s != '\n' ; ++s)
  329.         switch (*s)  {
  330.         case '\t':
  331.             n += t - n % t;
  332.             break;
  333.         case '\b':
  334.             if (n)
  335.                 --n;
  336.             break;
  337.         case '\r':
  338.             l = max(n, l);
  339.             n = 0;
  340.             break;
  341.         default:
  342.             if (isprint(*s))
  343.                 ++n;
  344.             break;
  345.         }
  346.     return max(l, n);
  347. }
  348.  
  349. #define more    n
  350. #define next    s++, n--
  351.  
  352. static    int    Val(char c, int b)
  353. {
  354.     int    n;
  355.  
  356.     if (isdigit(c))        n = c -    '0';
  357.     else  if (isalpha(c))    n = toupper(c) - ('A' -    10);
  358.     else            return(-1);
  359.     if (n >= b)        return(-1);    /* not in correct base */
  360.     return(n);
  361. }
  362.  
  363. imeth    gProcess()        /* string process  */
  364. {
  365.     char   *s, *d;
  366.     int     a, i, n;
  367.  
  368.     UPDATE_LEN;
  369.     s = d = iStr;
  370.     for (n=iLen ; more ; )
  371.         if (*s != '\\')  {
  372.             *d++ = *s;
  373.             next;
  374.         }  else  {
  375.             next;
  376.             if (!more)
  377.                 break;
  378.             switch (*s) {
  379.             case 'N':
  380.             case 'n':
  381.                 *d++ = '\n';
  382.                 next;
  383.                 break;
  384.             case 'T':
  385.             case 't':
  386.                 *d++ = '\t';
  387.                 next;
  388.                 break;
  389.             case 'B':
  390.             case 'b':
  391.                 *d++ = '\b';
  392.                 next;
  393.                 break;
  394.             case 'R':
  395.             case 'r':
  396.                 *d++ = '\r';
  397.                 next;
  398.                 break;
  399.             case 'F':
  400.             case 'f':
  401.                 *d++ = '\f';
  402.                 next;
  403.                 break;
  404.             case 'E':
  405.             case 'e':
  406.                 *d++ = 27;    /*  escape  */
  407.                 next;
  408.                 break;
  409.             case 'A':
  410.             case 'a':
  411.                 *d++ = 7;    /* BELL  */
  412.                 next;
  413.                 break;
  414.             case 'V':
  415.             case 'v':
  416.                 *d++ = '\v';    /*  vert tab ^K  */
  417.                 next;
  418.                 break;
  419.             case '^':
  420.                 next;
  421.                 if (!more)
  422.                     goto end;
  423.                 *d++ = tolower(*s) - ('a' - 1);
  424.                 next;
  425.                 break;
  426.             case 'X':
  427.             case 'x':
  428.                 *d = '\0';
  429.                 for (i = 0, next ; more && (a = Val(*s, 16)) != -1 && i != 2; next, ++i)
  430.                     *d = 16 * *d + a;
  431.                 ++d;
  432.                 break;
  433.             case 'D':
  434.             case 'd':
  435.                 *d = '\0';
  436.                 for (i = 0, next ; more && (a = Val(*s, 10)) != -1 && i != 3; next, ++i)
  437.                     *d = 10 * *d + a;
  438.                 ++d;
  439.                 break;
  440.             case '\0':
  441.                 break;
  442.             default:
  443.                 if (isdigit(*s)) {
  444.                     *d = '\0';
  445.                     for (i = 0; more && (a = Val(*s, 8)) != -1 && i != 3; next, ++i)
  446.                         *d = 8 * *d + a;
  447.                     ++d;
  448.                     break;
  449.                 }
  450.                 *d++ = *s;
  451.                 next;
  452.                 break;
  453.             }
  454.         }
  455.  end:
  456.     *d = '\0';
  457.     iLen = d - iStr;
  458.     FREE_UNUSED;
  459.     return self;
  460. }
  461.  
  462. imeth    gAppend(obj)
  463. {
  464.     char    *str;
  465.     int    len, need;
  466.  
  467.     if (!obj)
  468.         return self;
  469.     UPDATE_LEN;
  470.     len = get_string(obj, &str, "Append", 2);
  471.     need = iLen + 1 + len;
  472.     if (need > iSize)  {
  473.         if (iBlksz == 1)
  474.             iBlksz = ABS;
  475.         SETSIZE(need);
  476.         iStr = (char *) MA_realloc(iStr, iSize);
  477.     }
  478.     memcpy(iStr + iLen, str, len);
  479.     iLen += len;
  480.     iStr[iLen] = '\0';
  481.     return self;
  482. }
  483.  
  484. imeth    int    gWrite(char *buf, unsigned len)
  485. {
  486.     int    need;
  487.  
  488.     UPDATE_LEN;
  489.     need = iLen + 1 + len;
  490.     if (need > iSize)  {
  491.         if (iBlksz == 1)
  492.             iBlksz = ABS;
  493.         SETSIZE(need);
  494.         iStr = (char *) MA_realloc(iStr, iSize);
  495.     }
  496.     memcpy(iStr + iLen, buf, len);
  497.     iLen += len;
  498.     iStr[iLen] = '\0';
  499.     return len;
  500. }
  501.  
  502. imeth    int    gRead(char *buf, unsigned n)
  503. {
  504.     int    len;
  505.  
  506.     UPDATE_LEN;
  507.     len = n > (unsigned) iLen ? iLen : (int) n;
  508.     memcpy(buf, iStr, len);
  509.     memmove(iStr, iStr+len, iLen-len+1);
  510.     iLen -= len;
  511.     FREE_UNUSED;
  512.     return len;
  513. }
  514.  
  515. imeth    char    *gGets(char *buf, int n)
  516. {
  517.     int    len;
  518.  
  519.     UPDATE_LEN;
  520.     if (!iLen)
  521.         return NULL;
  522.     if (n <= 0)
  523.         return NULL;
  524.     if (n-- == 1)  {
  525.         *buf = '\0';
  526.         return buf;
  527.     }
  528.     for (len=0 ; len < iLen  &&  iStr[len++] != '\n' ; );
  529.     memcpy(buf, iStr, len);
  530.     memmove(iStr, iStr+len, iLen-len+1);
  531.     iLen -= len;
  532.     FREE_UNUSED;
  533.     buf[len] = '\0';
  534.     return buf;
  535. }
  536.  
  537. imeth    long    gAdvance(long n)
  538. {
  539.     int    len;
  540.  
  541.     UPDATE_LEN;
  542.     len = n > (long) iLen ? iLen : (int) n;
  543.     memmove(iStr, iStr+len, iLen-len+1);
  544.     iLen -= len;
  545.     FREE_UNUSED;
  546.     return (long) len;
  547. }
  548.  
  549. imeth    long    gPosition()
  550. {
  551.     USE(self);
  552.     return 0L;
  553. }
  554.  
  555. imeth    long    gLength()
  556. {
  557.     UPDATE_LEN;
  558.     return (long) iLen;
  559. }
  560.  
  561. imeth    int    gEndOfStream()
  562. {
  563.     UPDATE_LEN;
  564.     return !iLen;
  565. }
  566.  
  567. cvmeth    vSprintf(char *fmt, ...)
  568. {
  569.     char    buf[256];
  570.     MAKE_REST(fmt);
  571.  
  572.     vsprintf(buf, fmt, _rest_);
  573.     return gNewWithStr(self, buf);
  574. }
  575.  
  576. ivmeth    vBuild(char *f, ...)
  577. {
  578.     object    obj;
  579.     char    *str, *pbuf;
  580.     va_list        ap;
  581.     int    len, argn, tlen;
  582.     static    char    fun[] = "Build";
  583.     MAKE_REST(f);
  584.  
  585.     
  586.     /*  Calculate total length  */
  587.  
  588.     UPDATE_LEN;
  589.     if (f)
  590.         tlen = get_string((object) f, &str, fun, 2);
  591.     else
  592.         tlen = iLen;
  593.     ASSIGN_VA_LIST(ap, _rest_);
  594.     for (argn=3 ; obj = va_arg(ap, object) ; )
  595.         tlen += get_string(obj, &str, fun, argn++);
  596.  
  597.  
  598.     /*  Make sure buffer is big enough  */
  599.  
  600.     if (tlen >= iSize)  {
  601.         if (iBlksz == 1  &&  !f)
  602.             iBlksz = ABS;
  603.         SETSIZE(tlen + 1);
  604.         iStr = (char *) MA_realloc(iStr, iSize);
  605.     }
  606.  
  607.     
  608.     /*  Build string  */
  609.  
  610.     pbuf = iStr;
  611.     if (f)  {
  612.         len = get_string((object)f, &str, fun, 2);
  613.         if (len)
  614.             memcpy(pbuf, str, len);
  615.         pbuf += len;
  616.     }  else 
  617.         pbuf += iLen;
  618.     for (argn=3 ; obj = GetArg(object) ; )  {
  619.         len = get_string(obj, &str, fun, argn++);
  620.         if (len)  {
  621.             memcpy(pbuf, str, len);
  622.             pbuf += len;
  623.         }
  624.     }
  625.     *pbuf = '\0';
  626.     iLen = tlen;
  627.     return self;
  628. }
  629.  
  630. cvmeth    vBuild(...)
  631. {
  632.     object    obj;
  633.     char    *str, *pbuf;
  634.     va_list        ap;
  635.     int    len, argn, tlen=0;
  636.     static    char    fun[] = "Build";
  637.     object    newObj = gNew(super);
  638.     ivType    *iv = ivPtr(newObj);
  639.     MAKE_REST(self);
  640.  
  641.     
  642.     /*  Calculate total length  */
  643.  
  644.     ASSIGN_VA_LIST(ap, _rest_);
  645.     for (argn=2 ; obj = va_arg(ap, object) ; )
  646.         tlen += get_string(obj, &str, fun, argn++);
  647.  
  648.     /*  Create buffer  */
  649.  
  650.     iBlksz = 1;
  651.     SETSIZE(tlen + 1);
  652.     iStr = (char *) MA_malloc(iSize, &iStr);
  653.  
  654.     
  655.     /*  Build string  */
  656.  
  657.     pbuf = iStr;
  658.     for (argn=2 ; obj = GetArg(object) ; )  {
  659.         len = get_string(obj, &str, fun, argn++);
  660.         if (len)  {
  661.             memcpy(pbuf, str, len);
  662.             pbuf += len;
  663.         }
  664.     }
  665.     *pbuf = '\0';
  666.     iLen = tlen;
  667.     return newObj;
  668. }
  669.  
  670. static    int    get_string(object obj, char **str, char *fun, int argn)
  671. {
  672.     ivType    *iv2;
  673.     char    buf[80];
  674.  
  675.     if (!obj)  {
  676.         *str = "";
  677.         return 0;
  678.     } else if (!IsObj(obj))  {
  679.         *str = (char *) obj;
  680.         return strlen((char *) obj);
  681.     } 
  682.     if (!gIsKindOf(obj, CLASS))  {
  683.         sprintf(buf, "%s::String:  Arg %d incorrect type.\n", fun, argn);
  684.         gError(Dynace, buf);
  685.     }
  686.     iv2 = ivPtr(obj);
  687.     *str = iv2->iStr;
  688.     return iv2->iCalcLen ? (iv2->iLen=strlen(iv2->iStr)) : iv2->iLen;
  689. }
  690.  
  691. imeth    char    gCharValueAt(int i)
  692. {
  693.     UPDATE_LEN;
  694.     if (i < 0  ||  i > iLen)
  695.         gError(self, "CharValue::String:  Index out of range.\n");
  696.     return iStr[i];
  697. }
  698.  
  699. imeth    gChangeCharAt(int i, int c)
  700. {
  701.     UPDATE_LEN;
  702.     if (i < 0  ||  i > iLen)
  703.         gError(self, "ChangeCharAt::String:  Index out of range.\n");
  704.     if (i == iLen)  {
  705.         char    buf[2];
  706.         buf[0] = c;
  707.         buf[1] = '\0';
  708.         return gAppend(self, (object) buf);
  709.     }
  710.     iStr[i] = c;
  711.     return self;
  712. }
  713.  
  714. imeth    gToLower()
  715. {
  716.     char    *s;
  717.     int    len;
  718.  
  719.     UPDATE_LEN;
  720.     s = iStr;
  721.     len = iLen;
  722.     for ( ; len-- ; s++)
  723.         *s = tolower(*s);
  724.     return self;
  725. }
  726.  
  727. imeth    gToUpper()
  728. {
  729.     char    *s;
  730.     int    len;
  731.  
  732.     UPDATE_LEN;
  733.     s = iStr;
  734.     len = iLen;
  735.     for ( ; len-- ; s++)
  736.         *s = toupper(*s);
  737.     return self;
  738. }
  739.  
  740. imeth    gSubString(int beg, int num)
  741. {
  742.     object    obj = gNew(super CLASS);
  743.     ivType    *iv2 = ivPtr(obj);
  744.  
  745.     UPDATE_LEN;
  746.     if (beg < 0)
  747.         beg = iLen + beg;
  748.     if (num < 0)  {
  749.         beg += num + 1;
  750.         num = -num;
  751.     }
  752.  
  753.     if (beg >= iLen  ||  beg < 0)
  754.         num = 0;
  755.     else  {
  756.         int    n = iLen - beg;
  757.         num = num < n ? num : n;
  758.     }
  759.     iv2->iBlksz = 1;
  760.     SETSIZE(num+1);
  761.     iv2->iLen  = num;
  762.     iv2->iStr  = (char *) MA_malloc(iv2->iSize, &iv2->iStr);
  763.     if (num)
  764.         memcpy(iv2->iStr, iStr+beg, num);
  765.     iv2->iStr[num] = '\0';
  766.     return obj;
  767. }
  768.  
  769. imeth    gTake(int n)        /*  APL like take for string    */
  770. {
  771.     int     i, len;
  772.     char    *s;
  773.  
  774.     UPDATE_LEN;
  775.     len = n < 0 ? -n : n;
  776.     if (len == iLen)
  777.         return self;
  778.     if (len >= iSize)  {
  779.         SETSIZE(len + 1);
  780.         iStr = (char *) MA_realloc(iStr, iSize);
  781.     }
  782.     s = iStr;
  783.     if (n >= 0) {
  784.         for (i=iLen ; i < len ; i++)
  785.             s[i] = ' ';
  786.         goto end;
  787.     }
  788.     if (iLen < len) {
  789.         n = len - iLen;
  790.         memmove(s + n, s, iLen);
  791.         for (i = 0; i < n ; i++)
  792.             s[i] = ' ';
  793.         goto end;
  794.     }
  795.     memmove(s, s + (iLen - len), len);
  796.  end:
  797.     s[len] = '\0';
  798.     iLen = len;
  799.     FREE_UNUSED;
  800.     return self;
  801. }
  802.  
  803. imeth    gDrop(int n)        /* APL like drop for strings  */
  804. {
  805.     int    an;
  806.  
  807.     if (!n)
  808.         return self;
  809.     UPDATE_LEN;
  810.     an = n < 0 ? -n : n;
  811.     if (an >= iLen)
  812.         iLen = 0;
  813.     else  {
  814.         if (n > 0)
  815.             memmove(iStr, iStr + n, iLen - n);
  816.         iLen -= an;
  817.     }
  818.     iStr[iLen] = '\0';
  819.     FREE_UNUSED;
  820.     return self;
  821. }
  822.  
  823. #define     ISspace(c)  ((c) == ' ' || (c)    == '\t'    || (c) == '\n' || (c) == '\r')
  824.  
  825. imeth    gStripLeft()
  826. {
  827.     int    i, n;
  828.     char    *s = iStr;
  829.  
  830.     UPDATE_LEN;
  831.     for (i=0, n=iLen ; n  &&  ISspace(s[i]) ; ++i, --n);
  832.     if (!i)
  833.         return self;
  834.     if (n)
  835.         memmove(s, s + i, n);
  836.     iLen = n;
  837.     s[n] = '\0';
  838.     FREE_UNUSED;
  839.     return self;
  840. }
  841.  
  842. imeth    gStripRight()
  843. {
  844.     int    n;
  845.     char    *s = iStr;
  846.  
  847.     UPDATE_LEN;
  848.     for (n = iLen - 1 ; n >= 0 && ISspace(s[n]) ; n--);
  849.     s[iLen = n + 1] = '\0';
  850.     FREE_UNUSED;
  851.     return self;
  852. }
  853.  
  854. imeth    gStripCenter()
  855. {
  856.     int    i, n;
  857.     char    *s = iStr;
  858.     
  859.     UPDATE_LEN;
  860.     for (i=0, n=iLen ; n  &&  ISspace(s[i]) ; ++i, --n);
  861.     if (n  &&  i)
  862.         memmove(s, s + i, n);
  863.     for (--n ; n >= 0 && ISspace(s[n]) ; n--);
  864.     s[iLen = n + 1] = '\0';
  865.     FREE_UNUSED;
  866.     return self;
  867. }
  868.  
  869. imeth    gJustifyLeft()
  870. {
  871.     char    *s = iStr;
  872.     int    n, i;
  873.  
  874.     UPDATE_LEN;
  875.     n = iLen;
  876.     for (i=0 ; i < n  &&  ISspace(s[i]) ; ++i);
  877.     if (!i)
  878.         return self;
  879.     memmove(s, s + i, n-i);
  880.     for (i=n-i ; i < n ; )
  881.         s[i++] = ' ';
  882.     return self;
  883. }
  884.  
  885. imeth    gJustifyRight()
  886. {
  887.     char    *s = iStr;
  888.     int    n, i, p;
  889.  
  890.     UPDATE_LEN;
  891.     n = iLen;
  892.     for (i=n-1 ; i >= 0  &&  ISspace(s[i]) ; --i);
  893.     p = n - (i + 1);
  894.     if (!p)
  895.         return self;
  896.     memmove(s + p, s, n-p);
  897.     for (i=0 ; i < p ; )
  898.         s[i++] = ' ';
  899.     return self;
  900. }
  901.  
  902. imeth    gJustifyCenter()
  903. {
  904.     char    *s = iStr;
  905.     int    n, left, right, left2, p, i;
  906.  
  907.     UPDATE_LEN;
  908.     n = iLen;
  909.     for (left=0 ; left < n  &&  ISspace(s[left]) ; ++left);
  910.     for (right=0, i=n-1 ; i >= 0  &&  ISspace(s[i]) ; --i, ++right);
  911.     left2 = (left + right) / 2;
  912.     if (left2 == left)
  913.         return self;
  914.     if (left2 < left)  {    /*  shift left  */
  915.         p = left - left2;
  916.         memmove(s, s + p, n - p);
  917.         for (i=n-(p+1) ; i < n ; )
  918.             s[i--] = ' ';
  919.     } else {        /*  shift right  */
  920.         p = left2 - left;
  921.         memmove(s + p, s, n - p);
  922.         for (i=0 ; i < p ; )
  923.             s[i++] = ' ';
  924.     }
  925.     return self;
  926. }
  927.  
  928. imeth    int    gEqual(obj)
  929. {
  930.     char    *str;
  931.     int    len;
  932.  
  933.     if (EQ(self, obj))
  934.         return 1;
  935.     if (IsObj(obj))  {
  936.         ivType    *iv2;
  937.         if (NEQ(ClassOf(self), ClassOf(obj)))
  938.             return 0;
  939.         iv2 = ivPtr(obj);
  940.         if (iv2->iCalcLen)
  941.             iv2->iLen = strlen(iv2->iStr);
  942.         len = iv2->iLen;
  943.         str = iv2->iStr;
  944.     }  else  {
  945.         str = (char *) obj;
  946.         len = str ? strlen(str) : 0;
  947.     }
  948.     UPDATE_LEN;
  949.     if (iLen != len)
  950.         return 0;
  951.     if (len)
  952.         return memcmp(iStr, str, len) ? 0 : 1;
  953.     else
  954.         return 1;
  955. }
  956.  
  957. imeth    gCopy, gDeepCopy ()
  958. {
  959.     return gNewWithObj(ClassOf(self), self);
  960. }
  961.  
  962.  
  963.  
  964. /*
  965.  *
  966.  *    Copyright (c) 1993-1996 Algorithms Corporation
  967.  *    3020 Liberty Hills Drive
  968.  *    Franklin, TN  37067
  969.  *
  970.  *    ALL RIGHTS RESERVED.
  971.  *
  972.  *
  973.  *
  974.  */
  975.